#include "stdafx.h"

#include "RMSDirectX.h"
#include "channel.h"
#include <io.h>
#include "bmptoyuv.cpp"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

#define YCOLOR 20
#define UCOLOR 128
#define VCOLOR 128

CChannel::CChannel()
{
	YBuffer=YBufferS;
	UVBuffer=UVBufferS;
           OffY1 = (BYTE*) malloc(320*240);
           OffUV1 = (BYTE*) malloc(320*240);
           OffY2 = (BYTE*) malloc(640*480);
           OffUV2 = (BYTE*) malloc(640*480);
           OffY3 = (BYTE*) malloc(160*120);
           OffUV3 = (BYTE*) malloc(160*120);
		   OffY4 = (BYTE*) malloc(720*480);
           OffUV4 = (BYTE*) malloc(720*480);


           pTmp = (BYTE*) malloc(720*480);

           FrameSize = FS_320x240;

	memset(YBuffer, 198, CWX*CWY);
	memset(UVBuffer, 127, CWX*CWY);
#ifdef VC10
	width=320;
	height=240;
#endif
	for(int i = 0; i<8; i++)
	{
		pY[i] = NULL;
		pU[i] = NULL;
		pV[i] = NULL;
	}
	scaleinit = false;
}

CChannel::~CChannel()
{
  free(OffY1);
  free(OffY2);
  free(OffY3);
  free(OffY4);
  free(OffUV1);
  free(OffUV2);
  free(OffUV3);
  free(OffUV4);
  free(pTmp);
	for(int i = 0; i<8; i++)
	{
		if(pY[i]) 
			delete[] pY[i];
		if(pU[i])
			delete[] pU[i];
		if(pV[i])
			delete[] pV[i];
	}
	if(scaleinit) ScaleRelease(&m_sfd);
}


void CChannel::LoadFrameFromCamera(int nCamera, DWORD fs)
{
//---------------------- VC10 is always single channel!!!!----------------------------
#ifdef VC10    

    if((width == 320) && (height == 240))
	{
//        if((fs == FS_720x480))
//        {
//            YBuffer=YBufferS;
//            UVBuffer=UVBufferS;
//            
//            if(pY[nCamera] && pU[nCamera] && pV[nCamera])
//            {
//                BYTE* pYDst = YBuffer;
//                BYTE* pUDst = UVBuffer;
//                BYTE* pVDst = UVBuffer+CWX*CWY/2;
//                
//                BYTE* pYSrc = pY[nCamera];
//                BYTE* pUSrc = pU[nCamera];
//                BYTE* pVSrc = pV[nCamera];
//                
//                ScaleChannelUpX2(&m_sfd, pYSrc, pYDst, CWX*2, CH*2);
//                ScaleChannelUpX2(&m_sfd, pUSrc, pUDst, CWX, CH);
//                ScaleChannelUpX2(&m_sfd, pVSrc, pVDst, CWX, CH);
//            }
//            else
//            {
////                memset(YBuffer, 0, CX*CY);   - why???
////                memset(UVBuffer, 128, CX*CY); - what's for???
//            }
//        }
//		else 
		if((fs == FS_FULLSCREEN) || (fs == FS_640x480) || (fs == FS_720x480))
        {
            YBuffer=YBufferS;
            UVBuffer=UVBufferS;
            
            if(pY[nCamera] && pU[nCamera] && pV[nCamera])
            {
                BYTE* pYDst = YBuffer;
                BYTE* pUDst = UVBuffer;
                BYTE* pVDst = UVBuffer+CW*CH*2;
                
                BYTE* pYSrc = pY[nCamera];
                BYTE* pUSrc = pU[nCamera];
                BYTE* pVSrc = pV[nCamera];
                
                ScaleChannelUpX2(&m_sfd, pYSrc, pYDst, CW*2, CH*2);
                ScaleChannelUpX2(&m_sfd, pUSrc, pUDst, CW*2, CH);
                ScaleChannelUpX2(&m_sfd, pVSrc, pVDst, CW*2, CH);
            }
            else
            {
//                memset(YBuffer, 0, CX*CY);   - why???
//                memset(UVBuffer, 128, CX*CY); - what's for???
            }
        }
        else if(fs == FS_160x120)
        {
            YBuffer=YBufferS;
            UVBuffer=UVBufferS;
            
            if(pY[nCamera] && pU[nCamera] && pV[nCamera])
            {
                BYTE* pYDst = YBuffer;
                BYTE* pUDst = UVBuffer;
                BYTE* pVDst = UVBuffer+(CW/2*CH/4);
                
                BYTE* pYSrc = pY[nCamera];
                BYTE* pUSrc = pU[nCamera];
                BYTE* pVSrc = pV[nCamera];
                
                ScaleChannelDownX2(&m_sfd, pYSrc, pYDst, CW, CH);
                ScaleChannelDownX2(&m_sfd, pUSrc, pUDst, CW, CH/2);
                ScaleChannelDownX2(&m_sfd, pVSrc, pVDst, CW, CH/2);
            }
        }
        else
        {
            if(pY[nCamera] && pU[nCamera] && pV[nCamera])
            {
                    
                YBuffer=YBufferS;
                UVBuffer=UVBufferS;
                
                BYTE* pYDst = YBuffer;
                BYTE* pUDst = UVBuffer;
                BYTE* pVDst = UVBuffer+CW*CH/2;
                
                BYTE* pYSrc = pY[nCamera];
                BYTE* pUSrc = pU[nCamera];
                BYTE* pVSrc = pV[nCamera];
                
                memcpy(pYDst, pYSrc, CW*CH);
                memcpy(pUDst, pUSrc, CW*CH/2);
                memcpy(pVDst, pVSrc, CW*CH/2);
            }
        }
    }

    if((width == 640) && (height == 480))
	{
        if(pY[nCamera] && pU[nCamera] && pV[nCamera])
        {
			/*if((fs == FS_720x480) || (fs > 0x0000FFFF))
			{
				YBuffer=YBufferS;
				UVBuffer=UVBufferS;
    
				BYTE* pYDst = YBuffer;
				BYTE* pUDst = UVBuffer;
				BYTE* pVDst = UVBuffer+CWX*CWY/2;
    
				BYTE* pYSrc = pY[nCamera];
				BYTE* pUSrc = pU[nCamera];
				BYTE* pVSrc = pV[nCamera];
                
                ScaleChannelUpX2(&m_sfd, pYSrc, pYDst, CWX*2, CH*2);
                ScaleChannelUpX2(&m_sfd, pUSrc, pUDst, CWX, CH);
                ScaleChannelUpX2(&m_sfd, pVSrc, pVDst, CWX, CH);
			}  
			else */
				if((fs == FS_720x480) || (fs == FS_FULLSCREEN) || (fs == FS_640x480))
			{
				YBuffer=YBufferS;
				UVBuffer=UVBufferS;
    
				BYTE* pYDst = YBuffer;
				BYTE* pUDst = UVBuffer;
				BYTE* pVDst = UVBuffer+CX*CY/2;
    
				BYTE* pYSrc = pY[nCamera];
				BYTE* pUSrc = pU[nCamera];
				BYTE* pVSrc = pV[nCamera];
    
				memcpy(pYDst, pYSrc, CX*CY);
				memcpy(pUDst, pUSrc, CX*CY/2);
				memcpy(pVDst, pVSrc, CX*CY/2);
			}   
            else if(fs == FS_160x120)
			{
                // scale down x2
                YBuffer=YBufferS;
                UVBuffer=UVBufferS;
                
                BYTE* pYDst = YBuffer;
                BYTE* pUDst = UVBuffer;
                BYTE* pVDst = UVBuffer+(CW/2*CH/4);
                
                BYTE* pYSrc = pY[nCamera];
                BYTE* pUSrc = pU[nCamera];
                BYTE* pVSrc = pV[nCamera];

				ScaleChannelDownX2(&m_sfd, pYSrc, pYSrc, CW*2, CH*2);
				ScaleChannelDownX2(&m_sfd, pUSrc, pUSrc, CW*2, CH);
				ScaleChannelDownX2(&m_sfd, pVSrc, pVSrc, CW*2, CH);

				ScaleChannelDownX2(&m_sfd, pYSrc, pYDst, CW, CH);
				ScaleChannelDownX2(&m_sfd, pUSrc, pUDst, CW, CH/2);
				ScaleChannelDownX2(&m_sfd, pVSrc, pVDst, CW, CH/2);
            }
            else
			{
                // scale down x2
                YBuffer=YBufferS;
                UVBuffer=UVBufferS;
                
                BYTE* pYDst = YBuffer;
                BYTE* pUDst = UVBuffer;
                BYTE* pVDst = UVBuffer+CW*CH/2;
                
                BYTE* pYSrc = pY[nCamera];
                BYTE* pUSrc = pU[nCamera];
                BYTE* pVSrc = pV[nCamera];
                
//				memcpy(pYDst, pYSrc, CW*CH);
//				memcpy(pUDst, pUSrc, CW*CH/2);
//				memcpy(pVDst, pVSrc, CW*CH/2);
				ScaleChannelDownX2(&m_sfd, pYSrc, pYDst, CW*2, CH*2);
				ScaleChannelDownX2(&m_sfd, pUSrc, pUDst, CW*2, CH);
				ScaleChannelDownX2(&m_sfd, pVSrc, pVDst, CW*2, CH);
            }
        }
    }

	if((width == 720) && (height == 480))
	{
        if(pY[nCamera] && pU[nCamera] && pV[nCamera])
        {
			/*if((fs == FS_720x480) || (fs > 0x0000FFFF))
			{
				YBuffer=YBufferS;
				UVBuffer=UVBufferS;
    
				BYTE* pYDst = YBuffer;
				BYTE* pUDst = UVBuffer;
				BYTE* pVDst = UVBuffer+CWX*CWY;
    
				BYTE* pYSrc = pY[nCamera];
				BYTE* pUSrc = pU[nCamera];
				BYTE* pVSrc = pV[nCamera];
    
				memcpy(pYDst, pYSrc, CWX*CWY);
				memcpy(pUDst, pUSrc, CWX*CWY/2);
				memcpy(pVDst, pVSrc, CWX*CWY/2);
			}  
			else */
				if((fs == FS_720x480) || (fs == FS_FULLSCREEN) || (fs == FS_640x480))
			{
				YBuffer=YBufferS;
				UVBuffer=UVBufferS;
    
				BYTE* pYDst = YBuffer;
				BYTE* pUDst = UVBuffer;
				BYTE* pVDst = UVBuffer+CX*CY/2;
    
				BYTE* pYSrc = pY[nCamera];
				BYTE* pUSrc = pU[nCamera];
				BYTE* pVSrc = pV[nCamera];
    
				/*memcpy(pYDst, pYSrc, CX*CY);
				memcpy(pUDst, pUSrc, CX*CY/2);
				memcpy(pVDst, pVSrc, CX*CY/2);*/

				ScaleChannelDownX2(&m_sfd, pYSrc, pYDst, CW*2, CH*2);
				ScaleChannelDownX2(&m_sfd, pUSrc, pUDst, CW*2, CH);
				ScaleChannelDownX2(&m_sfd, pVSrc, pVDst, CW*2, CH);
			}   
            else if(fs == FS_160x120)
			{
                // scale down x2
                YBuffer=YBufferS;
                UVBuffer=UVBufferS;
                
                BYTE* pYDst = YBuffer;
                BYTE* pUDst = UVBuffer;
                BYTE* pVDst = UVBuffer+(CW/2*CH/4);
                
                BYTE* pYSrc = pY[nCamera];
                BYTE* pUSrc = pU[nCamera];
                BYTE* pVSrc = pV[nCamera];

				ScaleChannelDownX2(&m_sfd, pYSrc, pYSrc, CW*2, CH*2);
				ScaleChannelDownX2(&m_sfd, pUSrc, pUSrc, CW*2, CH);
				ScaleChannelDownX2(&m_sfd, pVSrc, pVSrc, CW*2, CH);

				ScaleChannelDownX2(&m_sfd, pYSrc, pYDst, CW, CH);
				ScaleChannelDownX2(&m_sfd, pUSrc, pUDst, CW, CH/2);
				ScaleChannelDownX2(&m_sfd, pVSrc, pVDst, CW, CH/2);
            }
            else
			{
                // scale down x2
                YBuffer=YBufferS;
                UVBuffer=UVBufferS;
                
                BYTE* pYDst = YBuffer;
                BYTE* pUDst = UVBuffer;
                BYTE* pVDst = UVBuffer+CW*CH/2;
                
                BYTE* pYSrc = pY[nCamera];
                BYTE* pUSrc = pU[nCamera];
                BYTE* pVSrc = pV[nCamera];
                
//				memcpy(pYDst, pYSrc, CW*CH);
//				memcpy(pUDst, pUSrc, CW*CH/2);
//				memcpy(pVDst, pVSrc, CW*CH/2);
				ScaleChannelDownX2(&m_sfd, pYSrc, pYDst, CW*2, CH*2);
				ScaleChannelDownX2(&m_sfd, pUSrc, pUDst, CW*2, CH);
				ScaleChannelDownX2(&m_sfd, pVSrc, pVDst, CW*2, CH);
            }
        }
    }  


//---------------------- standard client - multichannel ---------------------------------
#else
	if((fs == FS_FULLSCREEN) || (fs == FS_640x480))
	{
		if(pY[nCamera] && pU[nCamera] && pV[nCamera])
		{
			BYTE* pYDst = YBuffer;
			BYTE* pUDst = UVBuffer;
#ifdef _SCALE_MSK_
			BYTE* pVDst = UVBuffer+CW*CH*2;
#else
			BYTE* pVDst = UVBuffer+CW*CH/2;
#endif

			BYTE* pYSrc = pY[nCamera];
			BYTE* pUSrc = pU[nCamera];
			BYTE* pVSrc = pV[nCamera];

#ifdef _SCALE_MSK_
			ScaleChannelUpX2(&m_sfd, pYSrc, pYDst, CW*2, CH*2);
			ScaleChannelUpX2(&m_sfd, pUSrc, pUDst, CW*2, CH);
			ScaleChannelUpX2(&m_sfd, pVSrc, pVDst, CW*2, CH);
#else
			memcpy(pYDst, pYSrc, CW*CH);
			memcpy(pUDst, pUSrc, CW*CH/2);
			memcpy(pVDst, pVSrc, CW*CH/2);
#endif
		}
		else
		{
			memset(YBuffer, 0, CX*CY);
			memset(UVBuffer, 128, CX*CY);
		}
	}
	else
	{
		if(pY[nCamera] && pU[nCamera] && pV[nCamera])
		{
			BYTE* pYDst = YBuffer;
			BYTE* pUDst = UVBuffer;
			BYTE* pVDst = UVBuffer+CX*CY/2;

			BYTE* pYSrc = pY[nCamera];
			BYTE* pUSrc = pU[nCamera];
			BYTE* pVSrc = pV[nCamera];

			switch(nCamera)
			{
				case 0:
				case 4:
					pYDst += 2*CX + 2; 
					pUDst += CX + 1; 
					pVDst += CX + 1; 
					break;
				case 1:
				case 5:
					pYDst += 2*CX + 332;
					pUDst += CX + 166; 
					pVDst += CX + 166; 
					break;
				case 2:
				case 6:
					pYDst += 272*CX + 2; 
					pUDst += 136*CX + 1; 
					pVDst += 136*CX + 1; 
					break;
				case 3:
				case 7:
					pYDst += 272*CX + 332; 
					pUDst += 136*CX + 166; 
					pVDst += 136*CX + 166; 
					break;
				default:
					return;
			}

			for(int i = 0; i<CH; i++)
			{
				memcpy(pYDst, pYSrc, CW);
				memcpy(pUDst, pUSrc, CW/2);
				memcpy(pVDst, pVSrc, CW/2);

				pYDst+= CX; pUDst+= CX/2; pVDst+= CX/2;
				pYSrc+= CW; pUSrc+= CW/2; pVSrc+= CW/2;
			}
		}
	}
#endif
}

void CChannel::SetFrameSize(int NewFrameSize)
{
  if ((NewFrameSize==FS_320x240)||(NewFrameSize==FS_640x480)||(NewFrameSize==FS_720x480)||(NewFrameSize==FS_160x120)) FrameSize=NewFrameSize;
}

void CChannel::Size2up(BYTE* p0, BYTE* p1, int w0, int h0)
{
  int i,j;
  for(i=0; i<h0; i++)
    for(j=0; j<w0; j++)
    {
      pTmp[2*w0*2*i + 2*j] = p0[i*w0+j];
      pTmp[2*w0*2*i + 2*j+1] = p0[i*w0+j];
      pTmp[2*w0*(2*i+1) + 2*j] = p0[i*w0+j];
      pTmp[2*w0*(2*i+1) + 2*j+1] = p0[i*w0+j];
    }
  memcpy(p1, pTmp, w0*h0*4);
}

void CChannel::Size2dn(BYTE* p0, BYTE* p1, int w0, int h0)
{
  int i,j;
  for(i=0; i<h0/2; i++)
    for(j=0; j<w0/2; j++)
      pTmp[w0/2*i + j] = ((int)p0[w0*2*i+2*j]+p0[w0*(2*i+1)+2*j]+p0[w0*2*i+2*j+1]+p0[w0*(2*i+1)+2*j+1])/4;
  memcpy(p1, pTmp, w0*h0/4);
}


void CChannel::LoadFrameFromBMP(string filename)
{
  /*for(i=0; i<CX*CY; i++)
  {
    char c;
    if (i< CX*CY/4 - 10) c=20; else c=240;
    OffY[i] = c;
  }*/
  // for(i=0; i<CX*CY; i++) OffUV[i] = 128;

  if (filename=="")
  {
    OffName = filename;
    return;
  }


  FILE *f;
  f = fopen(filename.c_str(),"rb"); if (!f) return;
  int size=_filelength(_fileno(f));
  BYTE* pBMP = (BYTE*)malloc(size);
  fread(pBMP,size,1,f);
  fclose(f);

  LPBITMAPINFOHEADER lp=(LPBITMAPINFOHEADER)(pBMP+sizeof(BITMAPFILEHEADER));
  BYTE* pData = NULL;
  int ImgFrameSize=-1;
  if ( (lp->biWidth==320)&&(lp->biHeight==240) ) ImgFrameSize = FS_320x240;
  if ( (lp->biWidth==640)&&(lp->biHeight==480) ) ImgFrameSize = FS_640x480;
  if ( (lp->biWidth==720)&&(lp->biHeight==480) ) ImgFrameSize = FS_720x480;
  if ( (ImgFrameSize==-1) || (lp->biBitCount!=24) ) {
    MessageBox(NULL, "320x240 or 640x480 24-bit RGB bitmap is required","Cannot set custom image",MB_OK);
    goto error_exit;
  }

  pData = ((BYTE*)lp)+(lp->biSize);

  if (ImgFrameSize==FS_320x240)
  {
    SSE_BMP24ToYUV422(pData, OffY1, OffUV1, OffUV1+320*240/2, 320, 240, 320, 240, 320*3);

    Size2up(OffY1, OffY2, 320, 240);
    Size2up(OffUV1, OffUV2, 320/2, 240);
    Size2up(OffUV1+320*240/2, OffUV2+640*480/2, 320/2, 240);

	Size2up(OffY1, OffY4, 320, 240);
    Size2up(OffUV1, OffUV4, 320/2, 240);
    Size2up(OffUV1+320*240/2, OffUV4+720*480/2, 320/2, 240);

    Size2dn(OffY1, OffY3, 320, 240);
    Size2dn(OffUV1, OffUV3, 320/2, 240);
    Size2dn(OffUV1+320*240/2, OffUV3+160*120/2, 320/2, 240);
  } 
  else if (ImgFrameSize==FS_640x480)
  {
    SSE_BMP24ToYUV422(pData, OffY2, OffUV2, OffUV2+640*480/2, 640, 480, 640, 480, 640*3);

    Size2dn(OffY2, OffY1, 640, 480);
    Size2dn(OffUV2, OffUV1, 640/2, 480);
    Size2dn(OffUV2+640*480/2, OffUV1+320*240/2, 640/2, 480);

    Size2dn(OffY2, OffY3, 640, 480);
    Size2dn(OffUV2, OffUV3, 640/2, 480);
    Size2dn(OffUV2+640*480/2, OffUV3+160*120/2, 640/2, 480);

	Size2up(OffY2, OffY4, 640, 480);
    Size2up(OffUV2, OffUV4, 640/2, 480);
    Size2up(OffUV2+640*480/2, OffUV4+720*480/2, 720/2, 480);
  }
  if (ImgFrameSize==FS_720x480)
  {
    SSE_BMP24ToYUV422(pData, OffY4, OffUV4, OffUV4+720*480/2, 720, 480, 720, 480, 720*3);

    Size2dn(OffY4, OffY1, 720, 480);
    Size2dn(OffUV4, OffUV1, 720/2, 480);
    Size2dn(OffUV4+720*480/2, OffUV1+320*240/2, 720/2, 480);

    Size2dn(OffY4, OffY3, 720, 480);
    Size2dn(OffUV4, OffUV3, 720/2, 480);
    Size2dn(OffUV4+720*480/2, OffUV3+160*120/2, 720/2, 480);

	Size2dn(OffY4, OffY2, 720, 480);
    Size2dn(OffUV4, OffUV2, 720/2, 480);
    Size2dn(OffUV4+720*480/2, OffUV2+640*480/2, 720/2, 480);
  }

  OffName = filename;
error_exit:
  if (pBMP) free(pBMP);
}



void CChannel::SetActiveChannel(int nChannel)
{
	ClearChannels();
	m_nActiveChannel = nChannel;
#ifndef VC10
	switch(nChannel)
	{
	case 0:
		Line(0,0,0,238);
		Line(0,0,318,0);
		Line(0,238,318,238);
		Line(318,0,318,238);
		break;
	case 1:
		//Line(330,0,330,244);
		//Line(330,0,654,0);
		//Line(330,244,654,244);
		//Line(654,0,654,244);
		
		Line(320,0,320,238);
		Line(320,0,638,0);
		Line(320,238,638,238);
		Line(638,0,638,238);
		break;
	case 2:
		Line(0,240,0,478);
		Line(0,240,318,240);
		Line(0,478,318,478);
		Line(318,240,318,478);
		break;
	case 3:
		Line(320,240,320,478);
		Line(320,240,638,240);
		Line(320,478,638,478);
		Line(638,240,638,478);
		break;
	}
#endif
}

void CChannel::ClearChannels()
{
  if(OffName=="")
  {
    memset(YBuffer, 140, CWX*CWY);
    memset(UVBuffer, 128, CWX*CWY);
  } else
  {
//           char buf[128]; sprintf(buf, "%d", FrameSize);
//           ::MessageBox(NULL, buf, "frame size", MB_OK );

    if(FrameSize==FS_320x240)
    {
      memcpy(YBuffer, OffY1, 320*240);
      memcpy(UVBuffer, OffUV1, 320*240);
    } else
    if(FrameSize==FS_640x480)
    {
      memcpy(YBuffer, OffY2, 640*480);
      memcpy(UVBuffer, OffUV2, 640*480);
    } else
	if(FrameSize==FS_720x480)
    {
      memcpy(YBuffer, OffY4, 720*480);
      memcpy(UVBuffer, OffUV4, 720*480);
    } else
    if(FrameSize==FS_160x120)
    {
      memcpy(YBuffer, OffY3, 160*120);
      memcpy(UVBuffer, OffUV3, 160*120);
    }
  }
}

void CChannel::Line(int x0, int y0, int x1, int y1)
{
#ifndef VC10
	BYTE* ptrY = YBuffer + x0 + y0*CX;
	BYTE* ptrU = UVBuffer + x0 + y0*CX/2;
	BYTE* ptrV = UVBuffer + x0 + CX*CY/2 + y0*CX/2;

	if(x0 == x1)
	{
		for(int i = y0/2; i< y1/2; i++)
		{
			*ptrY = YCOLOR;
			*(ptrY+1) = YCOLOR;
			*(ptrY+CX) = YCOLOR;
			*(ptrY+CX+1) = YCOLOR;
			
			*ptrU = UCOLOR;
			*(ptrU+1) = UCOLOR;
			*ptrV = VCOLOR;
			*(ptrV+1) = VCOLOR;

			ptrY += CX*2;
			ptrU += CX;
			ptrV += CX;
		}
	}
	else if(y0 == y1)
	{
		for(int i = x0; i< x1; i++)
		{
			*ptrY = YCOLOR;
			*(ptrY+CX) = YCOLOR;

			*ptrU = UCOLOR;
			*ptrV = VCOLOR;

			ptrY ++;
			ptrU ++;
			ptrV ++;
		}
	}
#endif
}